plugin "regexExpander" (400.0, 400.0)

global { 
    global.padding = 5.0 
    global.CANVAS_WIDTH = 400.0
    global.CANVAS_HEIGHT = 400.0

    global.container = Rectangle {
        x : 0.0
        y : 0.0
        w : global.CANVAS_WIDTH
        h : global.CANVAS_HEIGHT
        color   : Colors.none
        strokeColor : Colors.none
        strokeWidth : 1.5
    }
}

Colors {
    Colors.black = rgba(0.0, 0.0, 0.0, 1.0)
    Colors.gray = rgba(0.8, 0.8, 0.8, 1.0)
    Colors.darkgray = rgba(0.6, 0.6, 0.6, 1.0)
    Colors.red = rgba(1.0, 0.0, 0.0, 1.0)
    Colors.yellow = rgba(1.0, 1.0, 0.0, 1.0)
    Colors.lightKhaki = rgba(0.941, 0.902, 0.549, 1.0)
    Colors.orange = rgba(1.0, 0.6, 0.0, 1.0)
    Colors.lightorange = rgba(1.0, 0.6, 0.0, 0.25)
    Colors.green = rgba(0.0, 1.0, 0.0, 1.0)
    Colors.blue = rgba(0.0, 0.0, 1.0, 1.0)
    Colors.lightblue = rgba(0.0, 0.0, 1.0, 0.25)
    Colors.cyan = rgba(0.0, 1.0, 1.0, 1.0)
    Colors.purple = rgba(0.5, 0.0, 0.5, 1.0)
    Colors.white = rgba(1.0, 1.0, 1.0, 1.0)
    Colors.none = rgba(0.0, 0.0, 0.0, 0.0)
    Colors.sky = rgba(0.42, 0.65, 0.77, 1.0)
    Colors.lightsky = rgba(0.252, 0.65, 0.77, 0.25)
    Colors.pink = rgba(0.78, 0.256, 0.53, 1.0)
    Colors.lightpink = rgba(0.78, 0.256, 0.53, 0.25)
    Colors.bluegreen = rgba(0.44, 0.68, 0.60, 1.0)
}

PathType t {
    t.color = randomColor()
    -- t.color = Colors.orange
}

DiffuseObject d {
    d.shape = Rectangle {
        angle  : 0
        color   : Colors.none
        -- strokeColor : Colors.none
        strokeColor : Colors.black
        strokeWidth : 1.5
        x : global.container.x
        y : global.container.y
        w : global.container.w
        h : global.container.h
    }
    d.layering = d.shape above s.container
}

-- No "in path" predicate because scene geometry shouldn't depend directly on a path
SpecularObject o
{
    -- create mirror shape and put it in scene
    o.shape = Image {
        w : 100.0
        h : 10.0
        path  : "mirror.svg"
        x: o.shape.x
        y: o.shape.centerY
    }
}

LightSource l {
    -- l.shape = Circle {
        -- color : Colors.lightKhaki
        -- r : 15.0
        -- strokeWidth : 0.0
    -- }
    l.shape = Image {
        w : 40.0
        h : 40.0
        r : max(l.shape.w, l.shape.h) / 2.0
        path  : "sun.svg"
    }
    l.text = Text {
        x : l.shape.x
        y : l.shape.y
        string : "L"
        color : Colors.black
    }
    l.textLayering = l.text above l.shape
}

Camera c {
    c.shape = Image {
        w : 20.0
        h : 20.0
        r : max(c.shape.w, c.shape.h) / 2.0
        path  : "eye.svg"
    }
    c.text = Text {
        string : "E"
        color : Colors.black
    }
    c.textLayering = c.text above c.shape
    c.positionFn = encourage near(c.shape, c.text, c.shape.r + c.shape.w / 2.0)
    c.containsFn = ensure contains(global.container, c.text, 0.0)
}

-- applies to all scene geometries
SceneGeometry o {
    o.containFn = ensure contains(global.container, o.shape)
    o.layering  = o.shape above global.container
}

-- HACK: to make diffuse room below everybody
DiffuseObject d {
    d.layering = d.shape below global.container
}

PathVertex v; Path ps
where InVP(v, p); OnLight(v); e:= CreateEdge(v, v0)
with PathVertex v0; PathEdge e; PathType p; LightSource L {
    -- Add padding between arrow and light source
    -- LOCAL.angle = atan2(v0.y - L.shape.y, v0.x - L.shape.x)
    -- v.x = L.shape.x + cos(LOCAL.angle) * (L.shape.r) 
    -- v.y = L.shape.y + sin(LOCAL.angle) * (L.shape.r)
    v.x = L.shape.x 
    v.y = L.shape.y 
}

-- going into the eye
PathVertex v; Camera c; Path ps
where InVP(v, p); OnEye(v); e:= CreateEdge(v0, v)
with PathVertex v0; PathEdge e; PathType p {
    LOCAL.angle = atan2(v0.y - c.shape.y, v0.x - c.shape.x)
    v.x = c.shape.x + cos(LOCAL.angle) * c.shape.r
    v.y = c.shape.y + sin(LOCAL.angle) * c.shape.r
    c.shape.rotation = LOCAL.angle
}

PathVertex v; Path ps
where InVP(v, p); Hits(v, o)
with PathType p; SpecularObject o {
    -- TODO: on border of mirror
    v.x = ?
    v.y = ?
}

PathVertex v; Path ps
where InVP(v, p); Hits(v, o)
with PathType p; DiffuseObject o {
    -- TODO: exclude corners
    v.x = ?
    v.y = ?
    v.onFn = ensure pointOn(v.x, v.y, o.shape, 0.0)
}

PathEdge e 
where e := CreateEdge(v1, v2); InVP(v1, t); InVP(v2, t)
with PathVertex v1, v2; PathType t
{
     -- draw an arrow from v1's location to v2's location
     e.shape = Arrow {
         startX : v1.x
         startY : v1.y
         endX   : v2.x
         endY   : v2.y
         -- color  : Colors.lightKhaki
         color  : t.color
         thickness : 1.5
         arrowheadSize: 0.7
     }
}

PathEdge e1; PathEdge e2; Path ps
where e1 := CreateEdge(v1, v2);
      e2 := CreateEdge(v2, v3);
      IsSpecular(v2);
      Hits(v2, o)
with PathVertex v1, v2, v3;
     SpecularObject o
{
    LOCAL.mirrorPadding = 1.0
    LOCAL.horizontalShift = sampleReal(o.shape.w / -2.0 + 20.0, o.shape.w / 2.0 - 20.0)
    override o.shape.rotation = mirrorAngle(e1.shape, e2.shape)
    override o.shape.x = mirrorPosX(e1.shape, e2.shape, v2.x, v2.y, o.shape.h / 2.0 + LOCAL.mirrorPadding, LOCAL.horizontalShift)
    override o.shape.centerY = mirrorPosY(e1.shape, e2.shape, v2.x, v2.y, o.shape.h / 2.0 + LOCAL.mirrorPadding, LOCAL.horizontalShift)
}

PathEdge e; SpecularObject o {
     -- ray should not intersect scene geometry
     LOCAL.disjointFn = ensure disjoint(o.shape, e.shape, 5.0)
}
PathEdge e; LightSource l {
     LOCAL.disjointFn = ensure disjoint(l.shape, e.shape, 5.0)
}
PathEdge e; Camera c {
    LOCAL.disjointFn1 = ensure disjoint(c.shape, e.shape, 5.0)
    LOCAL.disjointFn2 = ensure disjoint(c.text, e.shape, 5.0)
}

-- No two specular objects should overlap
SpecularObject o1; SpecularObject o2 {
    LOCAL.disjointFn = ensure disjoint(o1.shape, o2.shape, 10.0)
    LOCAL.repelFn = encourage repel(o1.shape, o2.shape, 0.001)
}

-- the camera and light source should be far away from each other
Camera c; LightSource l {
    LOCAL.repelFn = encourage repel(c.shape, l.shape, 0.01)
}


---------------------------NON-COMPILABLE CODE----------------------------------


/*
PathEdge e 
where e := CreateEdge(v1, v2)
with PathVertex v1, v2; IsDiffuse(v1); IsDiffuse(v2)
{
    -- TODO: make sure the angle is angle is not 0 or 180
}

Path p; Path ps
where In(p, S)  {
      -- make path sample color
      -- label path with its string
}

-- Path vertex with various kinds of bounces

PathVertex v; Path ps
where InVP(v, p) with Path p {
     -- v.location = (?, ?)
}

-- TODO: work out the Path???


-- Rays


PathEdge e; SceneGeometry o; Path ps {
     -- ray should not intersect scene geometry
}

-- Do something at bounce point

-- Two edges that share a vertex
PathEdge e1; PathEdge e2; Path ps
where InVE(v1, e1); InVE(v2, e1); InVE(v2, e2); InVE(v3, e2);
      Hits(v2, o)
with PathVertex v1, v2, v3;
     SceneGeometry o {
     -- draw bounce normal for all bounces
}

-- Do something at specular bounce point

*/
